/**

 @Name：基于layui的树型表格
 @Author：

 */
layui.link(layui.cache.base + '../css/layui-extends.css');

layui.define(['laytpl', 'laypage', 'layer', 'form'], function (exports) {

    var $ = layui.$
        , laytpl = layui.laytpl
        , laypage = layui.laypage
        , layer = layui.layer
        , form = layui.form


        //字符常量
        ,MOD_NAME='treeTable' , NONE = 'layui-none', ELEM_HEADER = '.layui-table-header', ELEM_BODY = '.layui-table-body', ELEM_MAIN = '.layui-table-main'

        ,ELEM_TOOL = '.layui-table-tool'


        , treeTable = {
            index: layui.treeTable ? (layui.table.index + 10000) : 0
            
            //事件监听
            ,on: function(events, callback){

              return layui.onevent.call(this, MOD_NAME, events, callback);
            }
        }


    //默认配置
    treeTable.config = {
        elem: '#treeTable'
        , loading: true //请求数据时，是否显示loading
        , cellMinWidth: 60 //所有单元格默认最小宽度
        , text: {
            none: '无数据'
        }

    };

    //thead区域模板
    var TPL_HEADER = [
            '<table cellspacing="0" cellpadding="0" border="0" class="layui-table">'
            , '<thead>'
            , '<tr>'
            , '{{# layui.each(d.data.cols, function(i, item){ }}'
            , '<th data-field="{{ item.field }}">'
            , '<div class="layui-table-cell laytable-cell-{{ d.index }}-{{ item.field }}">{{ item.title }}</div>'
            , '</th>'
            , '{{# }); }}'
            , '</tr>'
            , '</thead>'
            , '</table>'
        ].join('')


        //tbody区域模板
        , TPL_BODY = [
            '<table cellspacing="0" cellpadding="0" border="0" class="layui-table">'
            , '<tbody>'
            , '</tbody>'
            , '</table>'
        ].join('')


        //主模板
        , TPL_MAIN = [
            '<div class="layui-treetable layui-form layui-border-box layui-table-view" lay-filter="LAY-treetable-{{d.index}}">'
            , '<div class="layui-table-box">'
            , '<div class="layui-table-header">'
            , TPL_HEADER
            , '</div>'
            , '<div class="layui-table-body layui-table-main">'
            , TPL_BODY
            , '</div>'
            , '</div>'
            , '<style>'
            , '{{# '
            , 'layui.each(d.data.cols, function(i, item){ }}'
            , '.laytable-cell-{{d.index}}-{{item.field}}{ '
            , '{{# if(item.width){ }}'
            , 'width: {{item.width}}px;'
            , '{{# } }}'
            , ' }'
            , '{{# });'
            , '}}'
            , '</style>'
            , '</div>'
        ].join('')

    ,_WIN = $(window)
    ,_DOC = $(document);

    //表格渲染
    treeTable.render = function (settings) {
        var that = this
            , options
            , reElem;


        ++that.index;

        that.confing = options = $.extend(that.config, settings);

        options.elem = $(options.elem);

        options.where = options.where || {};

        //请求参数的自定义格式
        options.request = $.extend({}, options.request)

        //响应数据的自定义格式
        options.response = $.extend({
            statusName: 'code'
            , statusCode: 0
            , msgName: 'msg'
            , dataName: 'data'
            , countName: 'count'
        }, options.response);

        that.setArea(); //动态分配列宽高

        reElem = that.elem = $(laytpl(TPL_MAIN).render({
            data: options
            , index: that.index
        }));

        options.elem.replaceWith(reElem);
        that.config.elem = reElem;


        //各级容器
        that.layHeader = reElem.find(ELEM_HEADER);
        that.layMain = reElem.find(ELEM_MAIN);
        that.layBody = reElem.find(ELEM_BODY);
        that.layTool = reElem.find(ELEM_TOOL);


        that.pullData();
        that.events();

        that.haveInit ? that.scrollPatch() : setTimeout(function(){
                that.scrollPatch();
            }, 50);
        that.haveInit = true;


        if(options.height) that.fullSize(); //设置body区域高度


    }

    //动态分配列宽高
    treeTable.setArea = function () {
        var that = this
            , options = that.config
            , colNums = 0 //列个数
            , autoColNums = 0 //自动列宽的列个数
            , autoWidth = 0 //自动列分配的宽度
            , countWidth = 0 //所有列总宽度和
            , cntrWidth = function () { //获取容器宽度
            //如果父元素宽度为0（一般为隐藏元素），则继续查找上层元素，直到找到真实宽度为止
            parent = parent || options.elem.parent()

            var getWidth = function (parent) {
                var width, isNone;
                parent = parent || options.elem.parent()

                width = parent.width() - 15;
                try {
                    isNone = parent.css('display') === 'none';
                } catch (e) { }
                if (parent[0] && (!width || isNone)) return getWidth(parent.parent());
                return width;
            };
            return getWidth();
        }();

        var colsArr = options.cols//.concat().slice(1,options.cols.length);

        layui.each(colsArr, function (i, item) {
            if (item.width) {
                countWidth += item.width
            } else {
                autoColNums++;
            }
            colNums++;
        });
        autoWidth = (cntrWidth - countWidth) / autoColNums;

        layui.each(options.cols, function (i, item) {
            !item.width && (item.width = autoWidth - 2);
        });

        that.autoColNums = autoColNums; //记录自动列数

        //高度铺满：full-差距值
        if(options.height && /^full-\d+$/.test(options.height)){
            that.fullHeightGap = options.height.split('-')[1];
            options.height = _WIN.height() - that.fullHeightGap;
        }
    };

    //获取数据
    treeTable.pullData = function (loadIndex) {
        var that = this
            , options = that.config
            , request = options.request
            , response = options.response;

        if (options.url) { //获取动态数据
            var params = {};

            $.ajax({
                type: options.method || 'get'
                , url: options.url
                , data: $.extend(params, options.where)
                , dataType: 'json'
                , success: function (res) {
                    if (res[response.statusName] != response.statusCode) {
                        that.renderForm();
                        that.layMain.html('<div class="' + NONE + '">' + (res[response.msgName] || '返回的数据状态异常') + '</div>');
                    } else {
                        that.renderData(res, curr, res[response.countName]);
                    }
                    loadIndex && layer.close(loadIndex);
                    typeof options.done === 'function' && options.done(res, curr, res[response.countName]);
                }
                , error: function (e, m) {
                    that.layMain.html('<div class="' + NONE + '">数据接口请求异常</div>');
                    that.renderForm();
                    loadIndex && layer.close(loadIndex);
                }
            });


        } else if (options.data && options.data.constructor === Array) { //获取静态数据

            var res = {};

            res[response.dataName] = options.data;
            res[response.countName] = options.data.length;

            that.renderData(res, options.data.length);
            typeof options.done === 'function' && options.done(res, res[response.countName]);

        }



    }

    //数据渲染
    treeTable.renderData = function (res, count) {
        var that = this
            , options = that.config
            , data = that.formatData(res[options.response.dataName])

            //渲染表格结构
            , renderTable = function (item,levels) {
                var tds = [],
                    colIndent = '',
                    nodeTag = '',
                    level = String(levels).split('-').length;//item.level;

                if (level > 1) {
                    for (var i = 1; i < level; i++) {
                        colIndent += '<i class="laytable-tree-indent"></i>';
                    }
                }

                if (item.children) {
                    nodeTag = '<i class="layui-icon layui-tree-expander">&#xe625;</i>';
                } else {
                    nodeTag = '<i class="treetable-leaf"></i>'
                }

                layui.each(options.cols, function (j, col) {
                    var tdHtml = [],
                        fieldHtml;
                    if (col.field == 'nodename') {

                        tdHtml = [
                            '<td data-field="' + col.field + '" class="layui-tree-node">'
                            , '<div class="layui-table-cell laytable-cell-' + that.index + '-' + col.field + '">'
                            , colIndent
                            , nodeTag
                            , item[col.field]
                            , '</div>'
                            , '</td>'
                        ].join('');
                    } else {

                        //解析工具列模板
                        fieldHtml = (function(){

                            if(col.toolbar){
                                return laytpl($(col.toolbar).html()||'').render(item);
                            }

                            return col.templet ? function(){
                                return typeof col.templet === 'function' 
                                  ? col.templet(item)
                                : laytpl($(col.templet).html() || String(col.templet)).render(item) 
                              }() : item[col.field];


                        })();



                        tdHtml = [
                            '<td data-field="' + col.field + '">'
                            , '<div class="layui-table-cell laytable-cell-' + that.index + '-' + col.field + '">'
                            , fieldHtml
                            , '</div>'
                            , '</td>'
                        ].join('');
                    }


                    tds.push(tdHtml);

                });
                return tds.join('');
            }
            //渲染树型结构
            , renderTree = function () {

                var tbody = that.layMain.find('tbody'),
                    cacheData = that.cacheData = {};
                tbody.empty();
                (function (data, parentLevelId) {

                    var callee = arguments.callee;

                    var nodeNumber = 1;

                    for (var i in data) {

                        var node = data[i],
                            children = node.children,
                            tr,
                            trClass = '';

                        children && (trClass = 'treetable-expanded');

                        var levelId = parentLevelId ? parentLevelId + '-' + nodeNumber : nodeNumber;

                        tr = $('<tr data-level="' + levelId + '" class="' + trClass + '" data-nodeId="' + node.id + '">' + renderTable(node,levelId) + '</tr>');
                        //tr.data("nodeData", node);

                        tbody.append(tr);

                        cacheData[node.id] = { el: tr, data: node };

                        children && callee(children, levelId);

                        nodeNumber++;
                    }

                })(data);

                that.layBody.scrollTop(0);

            };
        renderTree();
        that.renderForm();


    }

    //渲染表单
    treeTable.renderForm = function (type) {
        form.render(type, 'LAY-treetable-' + this.index);
    }

    //格式化数据
    treeTable.formatData = function (data) {
        var cpData = data.concat(),

            getTreeData =  function (dataSource) {

                // 哈希结构数据 |key：节点id |value：对应节点
                var hashData = {};
                for (var i = 0; i < dataSource.length; i++) {
                    var node = dataSource[i];
                    hashData[node.id] = node;
                }

                // 根节点
                var rootNodes = {};
                for (var id in hashData) {
                    var node = hashData[id];
                    var pNode = hashData[node.parentId];
                    if (pNode) {
                        if (!pNode.children) pNode.children = {};
                        pNode.children[node.id] = node;
                    }
                    else {
                        rootNodes[node.id]=node;
                    }
                }
                return rootNodes;
            }

        return getTreeData(cpData);
    }

    //事件处理
    treeTable.events = function () {
        var that = this
            ,options = that.config
            ,filter = options.elem.attr('lay-filter')
            ,treeTd = that.layBody.find('td.layui-tree-node');
            

        // tree 折叠、展开
        treeTd.off('click').on('click', function () {
            var _this = $(this),
                tr = _this.parents("tr"),
                level = tr.data("level"),
                isExpanded = tr.hasClass('treetable-expanded'),
                trs = tr.nextAll("tr[data-level^='" + level + "']"),
                nodeId = tr.data('nodeid'),
                cacheData = that.cacheData,


                // 展开子节点
                expandChildNodes = function(nodeId, cacheData) {
                    var node = cacheData[nodeId],
                        children = node.data.children,
                        el = node.el,
                        isExpanded = el.hasClass('treetable-expanded');

                    el.show();
                    if (!isExpanded) return;

                    for (var i in children) {
                        expandChildNodes(i, cacheData);
                    }

                };


            if (isExpanded) {
                tr.removeClass('treetable-expanded').addClass('treetable-shrink');
                trs.hide();
            } else {
                tr.removeClass('treetable-shrink').addClass('treetable-expanded');
                expandChildNodes(nodeId, cacheData);
            }
        });

        //工具条操作事件
        that.layBody.off('click').on('click', '*[lay-event]', function(){
            var othis = $(this)
                ,tr = othis.parents("tr")
                ,level = tr.data("level")
                ,nodeId = tr.data("nodeid")
                ,data = that.cacheData[nodeId].data;


            layui.event.call(this, MOD_NAME, 'tool('+ filter +')',{
                data: data
                ,event: othis.attr('lay-event')      
                ,tr: tr
                ,nodeId: nodeId
                ,del: function(){
                    tr.nextAll("tr[data-level ^= '"+ level +"-']").remove();
                    tr.remove();
                }   

            });


        });

        //同步滚动条
        that.layMain.off('scroll').on('scroll', function(){
            var othis = $(this)
                ,scrollLeft = othis.scrollLeft();

            that.layHeader.scrollLeft(scrollLeft);


        });

    }


    //滚动条补丁
    treeTable.scrollPatch = function(){
        var that = this
            ,layMainTable = that.layMain.children('table')
            ,scollWidth = that.layMain.width() - that.layMain.prop('clientWidth') //纵向滚动条宽度
            ,scollHeight = that.layMain.height() - that.layMain.prop('clientHeight') //横向滚动条高度
            ,getScrollWidth = that.getScrollWidth(that.layMain[0]) //获取主容器滚动条宽度，如果有的话
            ,outWidth = layMainTable.outerWidth() - that.layMain.width(); //表格内容器的超出宽度

        //如果存在自动列宽，则要保证绝对填充满，并且不能出现横向滚动条

        if(that.autoColNums && outWidth < 5 && !that.scrollPatchWStatus){
            var th = that.layHeader.eq(0).find('thead th:last-child')
                ,field = th.data('field');
            that.getCssRule(field, function(item){

                var width = item.style.width || th.outerWidth();

                item.style.width = (parseFloat(width) - getScrollWidth - outWidth) + 'px';

                //二次校验，如果仍然出现横向滚动条
                if(that.layMain.height() - that.layMain.prop('clientHeight') > 0){
                    item.style.width = parseFloat(item.style.width) - 1 + 'px';
                }

                that.scrollPatchWStatus = true;
            });
        }



    };
    //获取cssRule
    treeTable.getCssRule = function(field, callback){
        var that = this
            ,style = that.elem.find('style')[0]
            ,sheet = style.sheet || style.styleSheet || {}
            ,rules = sheet.cssRules || sheet.rules;

        layui.each(rules, function(i, item){
            if(item.selectorText === ('.laytable-cell-'+ that.index +'-'+ field)){
                return callback(item), true;
            }
        });
    };

    //获取滚动条宽度
    treeTable.getScrollWidth = function(elem){
        return  elem.offsetWidth - elem.clientWidth;
    };

    //铺满表格主体高度
    treeTable.fullSize = function(){
        var that = this
            ,options = that.config
            ,height = options.height, bodyHeight;

        if(that.fullHeightGap){
            height = _WIN.height() - that.fullHeightGap;
            if(height < 135) height = 135;
            that.elem.css('height', height);
        }

        //tbody区域高度
        bodyHeight = parseFloat(height) - parseFloat(that.layHeader.height()) - 1;
        that.layMain.css('height', bodyHeight);
    }

    //切换数据 重载表格
    treeTable.dataReload = function(data){
        var that = this
            ,options = that.config
            ,res = {}
            ,request = options.request
            ,response = options.response;


        res[response.dataName] = data;
        res[response.countName] = data.length;
        that.renderData(res, data.length);
        that.events();
    }






    exports('treeTable', treeTable);
});

